package cn.john.hrm.controller;

import cn.john.hrm.doc.CourseDoc;
import cn.john.hrm.mapper.HighlightResultMapper;
import cn.john.hrm.query.CourseDocQuery;
import cn.john.hrm.query.PageList;
import cn.john.hrm.repository.CourseDocRepository;
import cn.john.hrm.util.AjaxResult;
import cn.john.hrm.vo.AggVo;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/search")
public class CourseDocController {
    @Autowired
    private CourseDocRepository courseDocRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;
    /**
     * 添加到es
     * @param courseDoc
     * @return
     */
    @PostMapping("/addCourseDoc")
    @PreAuthorize("hasAuthority('courseDoc:add')")
    public AjaxResult add(@RequestBody CourseDoc courseDoc) {
        // 保存
        courseDocRepository.save(courseDoc);
        return AjaxResult.me();
    }

    /**
     * 从es中删除
     * @param id
     * @return
     */
    @PostMapping("/deleteCourseDoc")
    @PreAuthorize("hasAuthority('courseDoc:delete')")
    public AjaxResult delete(@RequestBody Long id) {
        // 保存
        courseDocRepository.deleteById(id);
        return AjaxResult.me();
    }

    @PostMapping("/queryCourses")
    public AjaxResult queryCourses(@RequestBody CourseDocQuery query){
        // 创建query对象
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //* 高亮： 指定高亮字段 *//*
        HighlightBuilder.Field highlighfield = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
        // 名字高亮
        builder.withHighlightFields(highlighfield);
        // 高级查询
        String keyword = query.getKeyword();
        if (StringUtils.isNotBlank(keyword)) {
            boolQuery.must(QueryBuilders.multiMatchQuery(keyword,"name","courseTypeName","tenantName"));
        }
        String typeName = query.getCourseTypeName();
        if (StringUtils.isNotBlank(typeName)) {
            boolQuery.must(QueryBuilders.termQuery("courseTypeName", typeName));
        }
        String tenantName = query.getTenantName();
        if (StringUtils.isNotBlank(tenantName)) {
            boolQuery.must(QueryBuilders.termQuery("tenantName", tenantName));
        }
        //* 过滤： 以价格过滤 *//*
        // 小于等于最大价格
        Float priceMax = query.getPriceMax();
        if (priceMax != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(priceMax));
        }
        // 大于等于最小价格
        Float priceMin = query.getPriceMin();
        if (priceMin != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(priceMin));
        }
        builder.withQuery(boolQuery);
        //* 排序 *//*
        // 默认使用浏览量排序，排序字段有可能为空
        String field = query.getSortField();
        field = StringUtils.isNotBlank(field) ? field : "viewCount";
        FieldSortBuilder sortBuilder = new FieldSortBuilder(field);
        // 排序类型
        String sortType = query.getSortType();
        SortOrder order = StringUtils.isNotBlank(sortType)&&sortType.equals(SortOrder.DESC.toString())?SortOrder.DESC:SortOrder.ASC;
        builder.withSort(sortBuilder.order(order));
        //* 分页 *//*
        builder.withPageable(PageRequest.of(query.getPage()-1, query.getRows()));
        //* 聚合查询 *//*
        builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20));
        builder.addAggregation(AggregationBuilders.terms("courseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)).size(20));
        AggregatedPage<CourseDoc> courseDocs = elasticsearchTemplate.queryForPage(builder.build(), CourseDoc.class, highlightResultMapper);
        // 获取tenantNameAgg聚合查询的结果
        StringTerms tenantNameAgg = (StringTerms) courseDocs.getAggregation("tenantNameAgg");
        // 创建list集合封装机构名称聚合查询
        ArrayList<AggVo> tenantAggs = new ArrayList<>();
        List<StringTerms.Bucket> tenantList = tenantNameAgg.getBuckets();
        tenantList.forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setCount(bucket.getDocCount());
            aggVo.setName(bucket.getKeyAsString());
            tenantAggs.add(aggVo);
        });
        // 获取courseTypeAgg聚合查询的结果
        StringTerms typeNameAgg = (StringTerms) courseDocs.getAggregation("courseTypeAgg");
        //创建list集合封装机构名称聚合查询
        ArrayList<AggVo> typeAggs = new ArrayList<>();
        List<StringTerms.Bucket> typeList = typeNameAgg.getBuckets();
        typeList.forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setCount(bucket.getDocCount());
            aggVo.setName(bucket.getKeyAsString());
            typeAggs.add(aggVo);
        });
        // 创建一个map 封装两个聚合查询的结果
        HashMap<String,ArrayList<AggVo>> map = new HashMap<>();
        map.put("tenantAggs", tenantAggs);
        map.put("typeAggs", typeAggs);
        return AjaxResult.me().setResultObj(new PageList<>(courseDocs.getTotalElements(),courseDocs.getContent(),map));
    }
}
